package gsutil

import (
	"sync"
	"time"
)

type Snowflake struct {
	lock      sync.Mutex // 锁
	timestamp int64      // 时间戳 ，毫秒
	sequence  int64      // 序列号

	epoch            int64 // 设置起始时间(时间戳/毫秒)
	timestampBits    uint  // 时间戳占用位数
	datacenteridBits uint  // 数据中心id所占位数
	workeridBits     uint  // 机器id所占位数
	sequenceBits     uint  // 序列所占的位数

	timestampMax      int64 // 时间戳最大值
	sequenceMask      int64 // 支持的最大序列id数量
	workeridShift     uint  // 机器id左移位数
	datacenteridShift uint  // 数据中心id左移位数
	timestampShift    uint  // 时间戳左移位数
}

// 初始化，支持自定义配置
//
//	@epoch: 起始时间戳，毫秒
//	@timestampBits: 时间戳占用位数
//	@datacenteridBits: 数据中心id所占位数
//	@workeridBits: 机器id所占位数
//	@sequenceBits: 序列所占的位数
//
// 示例：
// 起始时间戳：2021-10-10 00:00:00
//
//	snowflake := NewSnowflakeWithOption(1635818871000, 41, 2, 7, 12)
//
// 生成id
//
//	id := snowflake.NextId()
//
// 输出id
//
//	fmt.Println(id)
//
// 注意：
//
//  1. 时间戳占用位数 + 数据中心id所占位数 + 机器id所占位数 + 序列所占的位数 = 64
//  2. 时间戳占用位数不能超过64位
//  3. 数据中心id所占位数不能超过64位
//  4. 机器id所占位数不能超过64位
//  5. 序列所占的位数不能超过64位
//  6. 时间戳占用位数 + 数据中心id所占位数 + 机器id所占位数 + 序列所占的位数不能超过64位
func NewSnowflakeWithOption(epoch int64, timestampBits, datacenteridBits, workeridBits, sequenceBits uint) *Snowflake {
	if (timestampBits + datacenteridBits + workeridBits + sequenceBits) > 64 {
		panic("timestampBits + datacenteridBits + workeridBits + sequenceBits 总和不能超过 64")
	}

	snowflake := &Snowflake{
		epoch:            epoch,
		timestampBits:    timestampBits,
		datacenteridBits: datacenteridBits,
		workeridBits:     workeridBits,
		sequenceBits:     sequenceBits,
	}
	snowflake.init()
	return snowflake
}

// 初始化	默认配置
//
//	@epoch: 起始时间戳，毫秒 默认：2021-10-10 00:00:00
//	@timestampBits: 时间戳占用位数，默认41
//	@datacenteridBits: 数据中心id所占位数，默认2
//	@workeridBits: 机器id所占位数，默认7
//	@sequenceBits: 序列所占的位数，默认12
//
// 示例：
// 起始时间戳：2021-10-10 00:00:00
//
//	snowflake := NewSnowflake()	// 默认配置
//
// 生成id
//
//	id := snowflake.NextId()
//
// 输出id
//
//	fmt.Println(id)
func NewSnowflake() *Snowflake {
	snowflake := &Snowflake{
		epoch:            int64(1635818871000),
		timestampBits:    uint(41),
		datacenteridBits: uint(2),
		workeridBits:     uint(7),
		sequenceBits:     uint(12),
	}
	snowflake.init()
	return snowflake
}

func (x *Snowflake) init() {
	x.timestampMax = int64(-1 ^ (-1 << x.timestampBits))
	x.sequenceMask = int64(-1 ^ (-1 << x.sequenceBits))
	x.workeridShift = x.sequenceBits
	x.datacenteridShift = x.sequenceBits + x.workeridBits
	x.timestampShift = x.sequenceBits + x.workeridBits + x.datacenteridBits
}

func (x *Snowflake) NextId() uint64 {
	x.lock.Lock()
	now := time.Now().UnixNano() / 1000000 // 转毫秒
	if x.timestamp == now {
		// 当同一时间戳（精度：毫秒）下多次生成id会增加序列号
		x.sequence = (x.sequence + 1) & x.sequenceMask
		if x.sequence == 0 {
			// 如果当前序列超出12bit长度，则需要等待下一毫秒
			// 下一毫秒将使用sequence:0
			for now <= x.timestamp {
				now = time.Now().UnixNano() / 1000000
			}
		}
	} else {
		// 不同时间戳（精度：毫秒）下直接使用序列号：0
		x.sequence = 0
	}

	t := now - x.epoch
	if t > x.timestampMax {
		x.lock.Unlock()
		return 0
	}

	x.timestamp = now
	r := uint64((t)<<x.timestampShift | (1 << x.datacenteridShift) | (1 << x.workeridShift) | (x.sequence))
	x.lock.Unlock()
	return r
}
